package com.rayo.keyboxdemo;

import android.os.Handler;
import android.os.Message;

import com.alibaba.fastjson.JSON;
import com.litesuits.common.utils.HexUtil;
import com.rayo.wallreader.data.BlackListKeyInfo;
import com.rayo.wallreader.data.KeyBasicInfo;
import com.rayo.wallreader.data.KeyEventInfo;
import com.rayo.wallreader.data.KeyType;
import com.rayo.wallreader.data.SettingKeyInfo;
import com.rayo.wallreader.data.SystemCodeKeyInfo;
import com.rayo.wallreader.data.UserKeyInfo;
import com.rayo.wallreader.gpio.OnRelayListener;
import com.rayo.wallreader.gpio.RelayBiz;
import com.rayo.wallreader.gpio.RelayThread;
import com.rayo.wallreader.jni.WallreaderJni;
import com.rayo.wallreader.serialport.OnPortListener;
import com.rayo.wallreader.serialport.PortClass;
import com.rayo.wallreader.serialport.ReaderPortThread;
import com.rayo.wallreader.utils.TimeUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static com.rayo.wallreader.data.PlugInReplyInfo.CLOSE_REPLY;
import static com.rayo.wallreader.data.PlugInReplyInfo.OPEN_REPLY;

/**
 * Created by yanghaojie on 2017/7/4.
 */

public class ReaderPresenter extends Handler {
    private int mCmd;
    private IReaderView mMainView;
    private boolean isRun;

    private boolean mResult;
    private KeyDefineData mKeyDefineData;

    private ReaderPortThread mReaderPortThread;
    private static ExecutorService mExecutorService = null;
    private List<PortClass> mPort  = new ArrayList<>();
    private int plugInRelay = 0;

    private static final int SHOW_MESSAGE = 0;
    private static final int IS_RUNNING = 1;
    private static final int CLEAN_MESSAGE = 2;

    private int[] plugInReader = {1};

    private RelayThread relayThread1 = new RelayThread(RelayBiz.RELAY1) {
        @Override
        protected void onSetRelay() {
            this.getmRelayBiz().openRelaySec(5, new OnRelayListener.OnOpenListener() {
                @Override
                public void openSuccess() {
                    setText("The Relay1 opened successfully\n");
                }

                @Override
                public void openFailed() {
                    setText("The Relay1 opened failed\n");
                }

                @Override
                public void closeSuccess() {
                    setText("The Relay1 is closed\n");
                }

                @Override
                public void closeFailed() {

                }
            });
        }
    };

    private RelayThread relayThread2 = new RelayThread(RelayBiz.RELAY2) {
        @Override
        protected void onSetRelay() {
            this.getmRelayBiz().openRelaySec(5, new OnRelayListener.OnOpenListener() {
                @Override
                public void openSuccess() {
                    setText("The Relay2 opened successfully\n");
                }

                @Override
                public void openFailed() {
                    setText("The Relay2 opened failed\n");
                }

                @Override
                public void closeSuccess() {
                    setText("The Relay2 is closed\n");
                }

                @Override
                public void closeFailed() {

                }
            });
        }
    };

    private class PlugInRelay implements Runnable {
        @Override
        public void run() {
            mReaderPortThread.setPlugInReply(plugInRelay, OPEN_REPLY);
            try {
                Thread.sleep(1000 * 3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            mReaderPortThread.setPlugInReply(plugInRelay, CLOSE_REPLY);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            setReader(14);
        }
    }

    public ReaderPresenter(IReaderView mainView) {
        mMainView = mainView;
        isRun = false;
        mResult = false;
        setText(WallreaderJni.getmInstance().version());
    }

    public void setPort(List<PortClass> port) {
        mPort = port;
    }

    public int[] getPlugInReader() {
        return plugInReader;
    }

    public void setPlugInReader(int[] plugInReader) {
        this.plugInReader = plugInReader;
    }

    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what) {
            case SHOW_MESSAGE:
                mMainView.setMsg((String) msg.obj);
                break;
            case IS_RUNNING:
                mMainView.showLoading(false);
                mMainView.showResultImage((boolean) msg.obj);
                isRun = false;
                break;
            case CLEAN_MESSAGE:
                mMainView.cleanMsg();
                break;
            default:
                break;
        }
    }

    public void destroy() {
        if (null != mExecutorService)
            mExecutorService.shutdown();
    }

    public void openSec() {
        obtainMessage(CLEAN_MESSAGE).sendToTarget();
        mExecutorService = Executors.newFixedThreadPool(2);
        mExecutorService.execute(relayThread1);
        mExecutorService.execute(relayThread2);
    }

    public void openPlugInRelay(int plugInNo) {
        plugInRelay = plugInNo;
        setReader(16);
    }

    private void setText(String txt) {
        obtainMessage(SHOW_MESSAGE, txt).sendToTarget();
    }

    private void setImage(boolean isSuccess) {
        obtainMessage(IS_RUNNING, isSuccess).sendToTarget();
    }

    public void setReader(int cmd) {
        if (cmd == 14 && isRun) {
            if (null != mExecutorService) {
                mExecutorService.shutdown();
                isRun = false;
                obtainMessage(IS_RUNNING, false).sendToTarget();
                mReaderPortThread = null;
                return;
            }
        }
        if (!isRun) {
            isRun = true;
            this.mCmd = cmd;
            mMainView.cleanMsg();
            start();

//            if (16 == mCmd) {
//                PlugInRelay plugInRelay = new PlugInRelay();
//                plugInRelay.run();
//            }
        } else {
            obtainMessage(SHOW_MESSAGE, "The reader is running").sendToTarget();
        }
    }
    private void start() {


        mMainView.showLoading(true);
        mKeyDefineData = new KeyDefineData();
        mReaderPortThread = new ReaderPortThread(mPort) {
            @Override
            protected void onSendNfcKeyReader(String s, int i) {
                setText("found nfc key");
                mKeyDefineData.newKeyBasicInfo();
                mKeyDefineData.getmKeyBasicInfo().setKeyType(KeyBasicInfo.NFC_KEY);
                openReader(this);
                this.stop();
            }

            @Override
            protected void onSendBleKeyReader(String s, int i) {
                setText("found ble key");
                mKeyDefineData.newKeyBasicInfo();
                mKeyDefineData.getmKeyBasicInfo().setKeyType(KeyBasicInfo.BLE_KEY);
                openReader(this);
                this.stop();
            }

            @Override
            protected void onSendCardReader(String s, int i, byte[] bytes) {
                String tagId = com.litesuits.common.utils.HexUtil.encodeHexStr(bytes);

                if (!tagId.equals("00000000")) {
                    setText("found M1 card "+tagId);
                    mResult = false;
                    setImage(mResult);
                    this.stop();
                }else {
                    return;
                }

            }

            @Override
            protected void onNoReader(String s, int i) {
//                setText("no reader " + String.valueOf(plugInReaderNo));
//                this.stop();
//                mResult = false;
//                setImage(mResult);
            }

            @Override
            protected void onPlugInRelay(String s, int i) {
//                if (plugInRelay == no) {
//                    mReaderPortThread.getmPortReadBiz().plugInReply(true, new OnPortListener.OnPlugInReplyListener() {
//                        @Override
//                        public void replySuccess() {
//
//                        }
//
//                        @Override
//                        public void replyFailed() {
//
//                        }
//                    });
//                    try {
//                        Thread.sleep(1000);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
//                    mReaderPortThread.getmPortReadBiz().plugInReply(false, new OnPortListener.OnPlugInReplyListener() {
//                        @Override
//                        public void replySuccess() {
//
//                        }
//
//                        @Override
//                        public void replyFailed() {
//
//                        }
//                    });
//                    this.stop();
//                    mResult = false;
//                    setImage(mResult);
//                }
            }

            @Override
            protected void onStopReader() {

            }

        };

        mExecutorService = Executors.newSingleThreadExecutor();
        mExecutorService.execute(mReaderPortThread);
    }

    private void openReader(ReaderPortThread mReaderPortThread) {
        switch (this.mCmd) {
            case 1:
                // Connect And Get Basic Infomation
                connectKey();
                setImage(mResult);
                break;
            case 2:
                // Make Setting Key
                if (connectKey()) {
                    mKeyDefineData.newSettingKey();
                    writeSettingKey(mKeyDefineData.getKeyBasicInfo(), mKeyDefineData.getSettingKeyInfo());
                    setText("Setting Key");
                    setText("Lock Id: " + JSON.toJSONString(mKeyDefineData.getSettingKeyInfo()));
                }
                setImage(mResult);
                break;
            case 3:
                // Make Emergency Key
                if (connectKey()) {
                    writeEmergencyKey(mKeyDefineData.newEmergencyKey());
                    setText("Emergency Key");
                    setText("Issue Key DateTime: "
                            + TimeUtils.dateFromNotYMDHMS(HexUtil.encodeHexStr(mKeyDefineData
                            .getmKeyBasicInfo().getKeyIssueTime())).toString());
                    setText("Start DateTime: "
                            + TimeUtils.dateFromNotYMDHMS(HexUtil.encodeHexStr(mKeyDefineData
                            .getmKeyBasicInfo().getBeginTime())).toString());
                    setText("End DateTime: "
                            + TimeUtils.dateFromNotYMDHMS(HexUtil.encodeHexStr(mKeyDefineData
                            .getmKeyBasicInfo().getEndTime())).toString());
                }
                setImage(mResult);
                break;
            case 4:
                // Make Event Key
                if (connectKey()) {
                    writeEventKey(mKeyDefineData.newEventKey());
                    setText("Event Key");
                }
                setImage(mResult);
                break;
            case 5:
                // Make Engineering Key
                if (connectKey()) {

                    writeEngineerKey(mKeyDefineData.newEngineeringKey());
                    setText("Engineering Key");
                    setText("Issue Key DateTime: "
                            + TimeUtils.dateFromNotYMDHMS(HexUtil.encodeHexStr(mKeyDefineData
                            .getmKeyBasicInfo().getKeyIssueTime())).toString());
                    setText("Start DateTime: "
                            + TimeUtils.dateFromNotYMDHMS(HexUtil.encodeHexStr(mKeyDefineData
                            .getmKeyBasicInfo().getBeginTime())).toString());
                    setText("End DateTime: "
                            + TimeUtils.dateFromNotYMDHMS(HexUtil.encodeHexStr(mKeyDefineData
                            .getmKeyBasicInfo().getEndTime())).toString());
                }
                setImage(mResult);
                break;
            case 6:
                // Make Black List Key
                if (connectKey()) {
                    mKeyDefineData.newBlackListKey();
                    writeBlackListKey(mKeyDefineData.getKeyBasicInfo(), mKeyDefineData.getBlackListKeyInfo());
                    setText("BlackList Key");
                    setText("BlackList: " + JSON.toJSONString(mKeyDefineData.getBlackListKeyInfo()));
                }
                setImage(mResult);
                break;
            case 7:
                // Make System Code Key
                if (connectKey()) {
                    mKeyDefineData.newSystemCodeKey();
                    writeSystemCodeKey(mKeyDefineData.getKeyBasicInfo(), mKeyDefineData.getSystemCodeKeyInfo());
                    setText("System-Code Key");
                    setText("New System Code: " + JSON.toJSONString(mKeyDefineData.getSystemCodeKeyInfo()));
                }
                setImage(mResult);
                break;
            case 8:
                // Make Read Lock Id Key
//                if (connectKey(mReaderPortThread, mKeyDefineData.newKeyBasicInfo())) {
//                    writeProKey(mReaderPortThread,
//                            mKeyDefineData.newKeyBasicInfo(),
//                            mKeyDefineData.newReadLockIdKey());
//                    setText("Read LockId Key");
//                }
                setImage(mResult);
                break;
            case 9:
                // Make Read Lock Serial Number Key
//                if (connectKey(mReaderPortThread, mKeyDefineData.newKeyBasicInfo())) {
//                    writeProKey(mReaderPortThread,
//                            mKeyDefineData.newKeyBasicInfo(),
//                            mKeyDefineData.newReadSerialKey());
//                    setText("Read Lock Serial Number Key");
//                }
                setImage(mResult);
                break;
            case 10:
                // Make User Key
                mKeyDefineData.getmKeyBasicInfo();
                mKeyDefineData.newUserKeyInfo();

                if (connectKey()) {
                    mKeyDefineData.newUserKeyInfo();
                    writeUserKey(mKeyDefineData.getmKeyBasicInfo(), mKeyDefineData.getUserKeyInfo());
                    setText("User Key");
                }
                setImage(mResult);
                break;
            case 11:
                // Read Key
                if (connectKey()) {
                    KeyType key = KeyType.fromInt(mKeyDefineData.getmKeyBasicInfo().getType());
                    readKey(key);
                }
                setImage(mResult);
                break;
            case 12:
                // Reset Key
                if (connectKey()) {
                    resetKey(mKeyDefineData.getKeyBasicInfo());
                    setText("Reset Key");
                }
                setImage(mResult);
                break;

            case 13:
                beep(mReaderPortThread, 1);
                setImage(mResult);
                break;
            case 15:
                if (connectKey()) {
                    keyCanOpen(mKeyDefineData.getmKeyBasicInfo(), 1, 1);
                }
                setImage(mResult);
                break;
            default:
                break;
        }
        if (this.mCmd == 13)
            return;
//        if (mResult) {
//            beep(mReaderPortThread, 1);
//        } else {
//            beep(mReaderPortThread, 2);
//        }
    }

    private void beep(ReaderPortThread mReaderPortThread, int type) {
        mReaderPortThread.getmPortReadBiz().beep(type, new OnPortListener.OnBeepListener() {

            @Override
            public void beepSuccess() {
                // TODO Auto-generated method stub
                setText("Beep successfylly \n");
                mResult = true;
            }

            @Override
            public void beepFailed() {
                // TODO Auto-generated method stub
                setText("Beep failed \n");
                mResult = false;
            }

        });
    }

    private boolean connectKey() {
        mReaderPortThread.getmPortReadBiz().findKey(mKeyDefineData.getmKeyBasicInfo(), new OnPortListener.OnFindListener() {
            @Override
            public void findSuccess() {
                String txt = "Find key successfully \n";
                txt += "Key Id: " + mKeyDefineData.getmKeyBasicInfo().getKeyId() + "\n";
                txt += "Key Type: " + String.format("%2X", mKeyDefineData.getmKeyBasicInfo().getType()) + "\n";
                txt += "Key Group Id: " + mKeyDefineData.getmKeyBasicInfo().getGroupId() + "\n";
                txt += "Key Version: " + mKeyDefineData.getmKeyBasicInfo().getVersion() + "\n";
                txt += "Key Serial Number: " + HexUtil.encodeHexStr(mKeyDefineData.getmKeyBasicInfo().getSerial()) + "\n";
                txt += "Key Time: " + TimeUtils.dateFromNotYMDWHMS(HexUtil.encodeHexStr(mKeyDefineData.getmKeyBasicInfo().getKeyTime())).getTime().toString() + "\n";
                setText(txt);
                mResult = true;
            }

            @Override
            public void findFailed() {
                setText("Find key failed \n");
                mResult = false;
            }
        });
        return mResult;
    }

    private void writeUserKey(KeyBasicInfo pKeyBasicInfo, UserKeyInfo pUserKeyInfo) {
        mReaderPortThread.getmPortReadBiz().writeUserKey(pKeyBasicInfo, pUserKeyInfo, new OnPortListener.OnWriteKeyListener() {
            @Override
            public void writeKeySuccess() {
                // TODO Auto-generated method stub
                setText("\nWrite user key successfully \n");
                mResult = true;
                setText("Open Lock Id 1-10, From 8:30 To 22:30");
            }

            @Override
            public void writeKeyFailed() {
                // TODO Auto-generated method stub
                setText("\nWrite user key failed \n");
                mResult = false;
            }
        });
    }

    private void writeSettingKey(KeyBasicInfo keyBasicInfo, final SettingKeyInfo settingKeyInfo) {
        mReaderPortThread.getmPortReadBiz().writeSettingKey(keyBasicInfo, settingKeyInfo, new OnPortListener.OnWriteKeyListener() {
            @Override
            public void writeKeySuccess() {
                setText("\nWrite setting key successfully \n");
                mResult = true;
            }

            @Override
            public void writeKeyFailed() {
                setText("\nWrite setting key failed \n");
                mResult = false;
            }
        });
    }

    private void writeEngineerKey(KeyBasicInfo keyBasicInfo) {
        mReaderPortThread.getmPortReadBiz().writeEngineerKey(keyBasicInfo, new OnPortListener.OnWriteKeyListener() {
            @Override
            public void writeKeySuccess() {
                setText("\nWrite EngineerKey key successfully \n");
                mResult = true;
            }

            @Override
            public void writeKeyFailed() {
                setText("\nWrite EngineerKey key failed \n");
                mResult = false;
            }
        });
    }

    private void writeEmergencyKey(KeyBasicInfo keyBasicInfo) {
        mReaderPortThread.getmPortReadBiz().writeEmergencyKey(keyBasicInfo, new OnPortListener.OnWriteKeyListener() {
            @Override
            public void writeKeySuccess() {
                setText("\nWrite Emergency key successfully \n");
                mResult = true;
            }

            @Override
            public void writeKeyFailed() {
                setText("\nWrite Emergency key failed \n");
                mResult = false;
            }
        });
    }

    private void writeEventKey(KeyBasicInfo keyBasicInfo) {
        mReaderPortThread.getmPortReadBiz().writeEventKey(keyBasicInfo, new OnPortListener.OnWriteKeyListener() {
            @Override
            public void writeKeySuccess() {
                setText("\nWrite Event key successfully \n");
                mResult = true;
            }

            @Override
            public void writeKeyFailed() {
                setText("\nWrite Event key failed \n");
                mResult = false;
            }
        });
    }

    private void writeBlackListKey(KeyBasicInfo keyBasicInfo, BlackListKeyInfo blackListKeyInfo) {
        mReaderPortThread.getmPortReadBiz().writeBlackListKey(keyBasicInfo, blackListKeyInfo, new OnPortListener.OnWriteKeyListener() {
            @Override
            public void writeKeySuccess() {
                setText("\nWrite blacklist key successfully \n");
                mResult = true;
            }

            @Override
            public void writeKeyFailed() {
                setText("\nWrite blacklist key failed \n");
                mResult = false;
            }
        });
    }

    private void writeSystemCodeKey(KeyBasicInfo keyBasicInfo, SystemCodeKeyInfo systemCodeKeyInfo) {
        mReaderPortThread.getmPortReadBiz().writeSystemCodeKey(keyBasicInfo, systemCodeKeyInfo, new OnPortListener.OnWriteKeyListener() {
            @Override
            public void writeKeySuccess() {
                setText("\nWrite system-code key successfully \n");
                mResult = true;
            }

            @Override
            public void writeKeyFailed() {
                setText("\nWrite system-code key failed \n");
                mResult = false;
            }
        });
    }

    private void resetKey(KeyBasicInfo keyBasicInfo) {
        mReaderPortThread.getmPortReadBiz().resetKey(keyBasicInfo, new OnPortListener.OnResetKeyListener() {
            @Override
            public void resetKeySuccess() {
                setText("\nreset key successfully \n");
                mResult = true;
            }

            @Override
            public void resetKeyFailed() {
                setText("\nreset key failed \n");
                mResult = false;
            }
        });
    }

    private void keyCanOpen(KeyBasicInfo keyBasicInfo, int lockId, int groupId) {
        mReaderPortThread.getmPortReadBiz().keyCanOpen(keyBasicInfo, lockId, groupId, new OnPortListener.OnWriteKeyListener() {

            @Override
            public void writeKeySuccess() {
                setText("\n key can open \n");
                mResult = true;
            }

            @Override
            public void writeKeyFailed() {
                setText("\n key can't open \n");
                mResult = false;
            }
        });
    }

    private void readKey(KeyType key) {
        if (null == key) {
            setText("UnKnow Key");
            return;
        }
        switch (key) {
            case USER_KEY:
                setText("User Key");
                setText("Issue Key DateTime: "
                        + TimeUtils.dateFromYMDHMS(HexUtil.encodeHexStr(mKeyDefineData
                        .getmKeyBasicInfo().getKeyIssueTime())).toString());
                setText("Start DateTime: "
                        + TimeUtils.dateFromYMDHMS(HexUtil.encodeHexStr(mKeyDefineData
                        .getmKeyBasicInfo().getBeginTime())).toString());
                setText("End DateTime: "
                        + TimeUtils.dateFromYMDHMS(HexUtil.encodeHexStr(mKeyDefineData
                        .getmKeyBasicInfo().getEndTime())).toString());

                readKeyEvent(mKeyDefineData.getmKeyBasicInfo(), mKeyDefineData.newKeyEventInfo());

                break;
            case SETTING_KEY:
                setText("Setting Key");
                readKeyEvent(mKeyDefineData.getmKeyBasicInfo(), mKeyDefineData.newKeyEventInfo());
                break;
            case SYSCODE_KEY:
                setText("System-Code Key");
                readKeyEvent(mKeyDefineData.getmKeyBasicInfo(), mKeyDefineData.newKeyEventInfo());
                break;
            case EVENT_KEY:
                setText("Event Key");
                break;
            case LOSS_KEY:
                setText("BlackList Key");
                break;
            case ENG_KEY:
                setText("Issue Key DateTime: "
                        + TimeUtils.dateFromYMDHMS(HexUtil.encodeHexStr(mKeyDefineData
                        .getmKeyBasicInfo().getKeyIssueTime())).toString());
                setText("Start DateTime: "
                        + TimeUtils.dateFromYMDHMS(HexUtil.encodeHexStr(mKeyDefineData
                        .getmKeyBasicInfo().getBeginTime())).toString());
                setText("End DateTime: "
                        + TimeUtils.dateFromYMDHMS(HexUtil.encodeHexStr(mKeyDefineData
                        .getmKeyBasicInfo().getEndTime())).toString());
                readKeyEvent(mKeyDefineData.getmKeyBasicInfo(), mKeyDefineData.newKeyEventInfo());
                break;
            case EMERGENCY_KEY:
                setText("Issue Key DateTime: "
                        + TimeUtils.dateFromYMDHMS(HexUtil.encodeHexStr(mKeyDefineData
                        .getmKeyBasicInfo().getKeyIssueTime())).toString());
                setText("Start DateTime: "
                        + TimeUtils.dateFromYMDHMS(HexUtil.encodeHexStr(mKeyDefineData
                        .getmKeyBasicInfo().getBeginTime())).toString());
                setText("End DateTime: "
                        + TimeUtils.dateFromYMDHMS(HexUtil.encodeHexStr(mKeyDefineData
                        .getmKeyBasicInfo().getEndTime())).toString());
                readKeyEvent(mKeyDefineData.getmKeyBasicInfo(), mKeyDefineData.newKeyEventInfo());
                break;
            case EMPTY_KEY:
                setText("Empty Key");
                break;
            default:
                break;
        }
    }

    private void readKeyEvent(KeyBasicInfo pKeyBasicInfo, KeyEventInfo pKeyEventInfo) {

        mReaderPortThread.getmPortReadBiz().readEvent(pKeyBasicInfo,
                pKeyEventInfo, new OnPortListener.OnReadEventListener() {

                    @Override
                    public void readEventSuccess() {
                        // TODO Auto-generated method stub
                        setText("\nRead key events successfully \n");
                        mResult = true;
                        for (KeyEventInfo.EventInfo e : mKeyDefineData
                                .getmKeyEventInfo().getEventList()) {
                            setText(e.toString());
                        }
                    }

                    @Override
                    public void readEventFailed() {
                        // TODO Auto-generated method stub
                        setText("\nRead key events failed \n");
                        mResult = false;
                    }

                });

    }


}
